package cqie.cn.frame.handler;

import cqie.cn.frame.utils.RetJson;
import cqie.cn.frame.utils.RetJsonUtils;
import cqie.cn.frame.exception.BusinessException;
import cqie.cn.frame.exception.FileException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.validation.ValidationException;
import java.io.IOException;
import java.util.List;

/**
 * @author 王林
 * @version 1.0
 * @date 2021-09-06 周一
 * @time 13:23
 * @description 全局异常处理类
 */
// @RestControllerAdvice注解包含了@ControllerAdvice注解和@ResponseBody注解
//@RestControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final String logExceptionFormat = "Capture Exception By GlobalExceptionHandler: Code: %s Detail: %s";
    private final static Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 判断错误是否是已定义的已知错误，不是则由未知错误代替，同时记录在log中
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    public RetJson BusinessException(BusinessException e) {

        LOGGER.error("【系统异常】{}", e);
        return RetJsonUtils.error(e.getCode(), e.getMsg());
    }

    /**
     * token过期异常
     *
     * @param ex
     * @return
     */
//    @ExceptionHandler(JWTVerificationException.class)
//    public RetJson FileException(JWTVerificationException ex) {
//
//        LOGGER.error("【系统异常】{}", ex);
//        return resultFormat(987, "登陆信息过期", ex);
//    }

    /**
     * 文件下载异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(FileException.class)
    public RetJson FileException(FileException ex) {

        LOGGER.error("【系统异常】{}", ex);
        return resultFormat(988, ex.getMessage(), ex);
    }

    /**
     * 文件上传异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public RetJson MaxUploadSizeExceededException(org.springframework.web.multipart.MaxUploadSizeExceededException ex) {

        LOGGER.error("【系统异常】{}", ex);
        return resultFormat(989, "文件上传异常(大小限制10M)", ex);
    }

    /**
     * javax.validation @Valid注解抛出的异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(ValidationException.class)
    public RetJson ValidationException(javax.validation.ValidationException ex) {
        LOGGER.error("【系统异常】{}", ex);
        return RetJsonUtils.error(991, ex.getMessage());
    }

    //空指针异常
    @ExceptionHandler(NullPointerException.class)
    public RetJson nullPointerExceptionHandler(NullPointerException ex) {
        return resultFormat(992, "空指针异常", ex);
    }

    //类型转换异常
    @ExceptionHandler(ClassCastException.class)
    public RetJson classCastExceptionHandler(ClassCastException ex) {
        return resultFormat(993, "类型转换异常", ex);
    }

    //IO异常
    @ExceptionHandler(IOException.class)
    public RetJson iOExceptionHandler(IOException ex) {
        return resultFormat(994, "IO异常", ex);
    }

    //未知方法异常
    @ExceptionHandler(NoSuchMethodException.class)
    public RetJson noSuchMethodExceptionHandler(NoSuchMethodException ex) {
        return resultFormat(995, "未知方法异常", ex);
    }

    //数组越界异常
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public RetJson indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        return resultFormat(996, "数组越界异常", ex);
    }

    //栈溢出     Error
    @ExceptionHandler({StackOverflowError.class})
    public RetJson requestStackOverflow(StackOverflowError ex) {
        return resultFormat(997, "栈溢出", ex);
    }

    //运行时异常
    @ExceptionHandler(RuntimeException.class)
    public RetJson runtimeExceptionHandler(RuntimeException ex) {
        return resultFormat(998, "运行时异常", ex);
    }

    //其他错误
    @ExceptionHandler({Exception.class})
    public RetJson exception(Exception ex) {
        return resultFormat(999, "其他错误", ex);
    }

    //400错误
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public RetJson requestNotReadable(HttpMessageNotReadableException ex) {
        System.out.println("400..requestNotReadable");
        return resultFormat(400, "400错误", ex);
    }

    //400错误
    @ExceptionHandler({TypeMismatchException.class})
    public RetJson requestTypeMismatch(TypeMismatchException ex) {
        System.out.println("400..TypeMismatchException");
        return resultFormat(400, "400错误", ex);
    }

    //400错误
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public RetJson requestMissingServletRequest(MissingServletRequestParameterException ex) {
        System.out.println("400..MissingServletRequest");
        return resultFormat(400, "400错误", ex);
    }

    //405错误
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public RetJson request405(HttpRequestMethodNotSupportedException ex) {
        return resultFormat(405, "405错误", ex);
    }

    //406错误
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public RetJson request406(HttpMediaTypeNotAcceptableException ex) {
        System.out.println("406...");
        return resultFormat(406, "406错误", ex);
    }

    //500错误
    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
    public RetJson server500(RuntimeException ex) {
        System.out.println("500...");
        return resultFormat(500, "500错误", ex);
    }

    /**
     * 其他错误
     * org.springframework.validation  @valid注解抛出的异常    validation
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({BindException.class})
    public RetJson bindException(BindException ex) {

        //TODONE  想要处理时间格式不对的异常，但是会把其他格式错误异常也处理，先不改？
        StringBuilder stringBuilder = new StringBuilder();
        //获取并拼接所有错误信息
        BindingResult bindingResult = ex.getBindingResult();
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        for (ObjectError item : allErrors) {
            stringBuilder.append(item.getDefaultMessage())
                    .append(',');
        }
        //删除最后一个逗号
        stringBuilder.deleteCharAt(stringBuilder.length() - 1);

//        System.out.println(ex.getMessage());

        return RetJsonUtils.error(990, stringBuilder.toString());
//        return RetJsonUtils.error(990, "参数格式不对哦");
    }

    private <T extends Throwable> RetJson resultFormat(Integer code, String msg, T ex) {
        ex.printStackTrace();
        LOGGER.error(String.format(logExceptionFormat, code, ex.getMessage()));
        return RetJsonUtils.error(code, msg);
    }

}